﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SuiteDemo
{
    public enum ATMType
    {
        Invalid, ABC, BOC, ICBC
    }

    public enum CardType
    {
        Invalid, Deposit, Withdraw, Both
    }

    public enum CmdType
    {
        Invalid, Deposit, Withdraw
    }

    public class ATM
    {
        private ATMType mType;
        private CmdType cType;
        private Card card;
        private int nErrPswd;

        public static ATM Instance;

        public ATM(ATMType t)
        {
            mType = t;
            nErrPswd = 0;
        }

        public ATMType GetATMType()
        {
            return mType;
        }

        public CmdType GetCmdType()
        {
            return cType;
        }

        public Card GetCard()
        {
            return card;
        }

        public int GetErrorCount()
        {
            return nErrPswd;
        }

        public void InsertCard(Card c)
        {
            card = c;
        }

        public void EnterPswd(string pswd)
        {
            if (card.IsValidPswd(pswd))
                nErrPswd = 0;
            else
            {
                nErrPswd++;
                if (nErrPswd == 3) SUT.Says("3 continuous error");
            }
        }

        public void SelectCmd(CmdType cmd)
        {
            if (cmd == CmdType.Invalid)
                SUT.Says("Invalid command");
            else
                cType = cmd;
        }

        public void DoCmd(double sum)
        {
            if (card != null)
                card.DoCmd(cType, sum);
        }

        public bool HasPermission()
        {
            return card.HasPermision(cType);
        }

        public double GetLimit()
        {
            switch(mType)
            {
                case ATMType.ABC:
                    return 1000;
                case ATMType.BOC:
                    return 2000;
                case ATMType.ICBC:
                    return 3000;
                default:
                    return -1;
            }
        }
    }

    public class Card
    {
        private ATMType mtype;
        private CardType ctype;
        private string pswd;
        private double balance;

        public Card(CardType ct, string cpd, double cbal)
        {
            if (ct == CardType.Invalid)
                SUT.Says("Invalid card type");
            else
            {
                mtype = ATM.Instance.GetATMType();
                ctype = ct;
                pswd = cpd;
                balance = cbal;
            }
        }

        public bool IsValidPswd(string pswd)
        {
            return (this.pswd == pswd);
        }

        public double GetBalance()
        {
            return balance;
        }

        public void DoCmd(CmdType cmd, double sum)
        {
            switch(cmd)
            {
                case CmdType.Deposit:
                    if (!HasPermision(cmd))
                    {
                        SUT.Says("Not enough card permission");
                        return;
                    }
                    DoDeposit(sum);
                    break;
                case CmdType.Withdraw:
                    if (!HasPermision(cmd))
                    {
                        SUT.Says("Not enough card permission");
                        return;
                    }
                    DoWithdraw(sum);
                    break;
                case CmdType.Invalid:
                default:
                    break;
            }
        }

        public bool HasPermision(CmdType cmd)
        {
            switch (cmd)
            {
                case CmdType.Deposit:
                    return !(ctype != CardType.Deposit && ctype != CardType.Both);
                case CmdType.Withdraw:
                    return !(ctype != CardType.Withdraw && ctype != CardType.Both);
                case CmdType.Invalid:
                default:
                    return true;
            }
        }

        private void DoDeposit(double sum)
        {
            if (sum < 0)
                SUT.Says("Deposit with negative value");
            else if (sum > ATM.Instance.GetLimit())
                SUT.Says("Larger than ATM's limit");
            else
                balance += sum;
        }

        private void DoWithdraw(double sum)
        {
            if (sum < 0)
                SUT.Says("Withdraw with negative value");
            else if (sum > ATM.Instance.GetLimit())
                SUT.Says("Larger than ATM's limit");
            else if (sum > balance)
                SUT.Says("Withdraw too much money");
            else
                balance += sum;
        }
    }

    public class SUT
    {
        public static bool IsError = false;       
        public static void Says(string error)
        {
            IsError = true;
            //Console.WriteLine(error);
        }
    }
}
